package cn.turboinfo.fuyang.api.provider.common.service.impl.user;

import cn.turboinfo.fuyang.api.domain.common.service.user.*;
import cn.turboinfo.fuyang.api.entity.common.enumeration.common.EntityObjectType;
import cn.turboinfo.fuyang.api.entity.common.enumeration.user.LoginCheckType;
import cn.turboinfo.fuyang.api.entity.common.enumeration.user.LoginNameType;
import cn.turboinfo.fuyang.api.entity.common.enumeration.user.UserType;
import cn.turboinfo.fuyang.api.entity.common.exception.user.UserTypeRelException;
import cn.turboinfo.fuyang.api.entity.common.pojo.user.SysUser;
import cn.turboinfo.fuyang.api.entity.common.pojo.user.UserCredential;
import cn.turboinfo.fuyang.api.entity.common.pojo.user.UserLoginCreator;
import cn.turboinfo.fuyang.api.entity.common.pojo.user.UserTypeRel;
import cn.turboinfo.fuyang.api.provider.common.repository.database.user.UserTypeRelDAO;
import cn.turboinfo.fuyang.api.provider.common.repository.database.user.UserTypeRelPO;
import lombok.RequiredArgsConstructor;
import lombok.val;
import net.sunshow.toolkit.core.qbean.api.request.QPage;
import net.sunshow.toolkit.core.qbean.api.request.QRequest;
import net.sunshow.toolkit.core.qbean.api.response.QResponse;
import net.sunshow.toolkit.core.qbean.helper.service.impl.AbstractQServiceImpl;
import org.apache.commons.lang3.StringUtils;
import org.springframework.data.domain.Page;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.time.LocalDateTime;
import java.util.List;
import java.util.Optional;
import java.util.stream.Collectors;

@RequiredArgsConstructor
@Service
public class UserTypeRelServiceImpl extends AbstractQServiceImpl<UserTypeRel> implements UserTypeRelService {
    private final UserTypeRelDAO userTypeRelDAO;

    private final SysUserRoleService sysUserRoleService;

    private final UserLoginService userLoginService;

    private final SysUserService sysUserService;

    private final UserCredentialService userCredentialService;

    @Override
    public List<UserTypeRel> findByUserId(Long userId) {
        return convertStreamQBeanToList(userTypeRelDAO.findByUserId(userId).stream());
    }

    /**
     * 创建公司和用户关联
     */
    @Override
    @Transactional
    public UserTypeRel createCompanyRel(Long userId, Long companyId) throws UserTypeRelException {
        // 验证关联关系是否已存在 已存在就不操作直接返回
        Optional<UserTypeRelPO> optional = userTypeRelDAO.findByUserIdAndUserTypeAndObjectTypeAndObjectId(userId, UserType.Company, EntityObjectType.COMPANY, companyId);
        if (optional.isPresent()) {
            return convertQBean(optional.get());
        }

        // 一个用户只能关联一个公司
        if (!userTypeRelDAO.findByUserIdAndUserType(userId, UserType.Company).isEmpty()) {
            throw new UserTypeRelException("当前用户已关联过公司");
        }

        UserTypeRelPO po = new UserTypeRelPO();

        po.setUserType(UserType.Company);
        po.setUserId(userId);
        po.setObjectType(EntityObjectType.COMPANY);
        po.setObjectId(companyId);

        // 一个事务内完成角色绑定
        sysUserRoleService.assignByCode(po.getUserId(), po.getUserType().getRoleCode());

        // 添加后台登录方式
        assignAdminUserLogin(userId);

        // 添加小程序登录方式
        assignMiniUserLogin(userId);

        return convertQBean(userTypeRelDAO.save(po));
    }

    @Override
    public boolean hasCompanyRel(Long userId, Long companyId) {
        return userTypeRelDAO.findByUserIdAndUserTypeAndObjectTypeAndObjectId(userId, UserType.Company, EntityObjectType.COMPANY, companyId).isPresent();
    }

    @Override
    @Transactional
    public UserTypeRel createStaffRel(Long userId, Long staffId) throws UserTypeRelException {
        // 验证关联关系是否已存在 已存在就不操作直接返回
        Optional<UserTypeRelPO> optional = userTypeRelDAO.findByUserIdAndUserTypeAndObjectTypeAndObjectId(userId, UserType.Staff, EntityObjectType.STAFF, staffId);
        if (optional.isPresent()) {
            return convertQBean(optional.get());
        }

        // 一个用户只能关联一个家政员
        if (!userTypeRelDAO.findByUserIdAndUserType(userId, UserType.Staff).isEmpty()) {
            throw new UserTypeRelException("当前用户已关联过家政员");
        }

        UserTypeRelPO po = new UserTypeRelPO();

        po.setUserType(UserType.Staff);
        po.setUserId(userId);
        po.setObjectType(EntityObjectType.STAFF);
        po.setObjectId(staffId);

        // 一个事务内完成角色绑定
        sysUserRoleService.assignByCode(po.getUserId(), po.getUserType().getRoleCode());

        // 添加后台登录方式
        // assignAdminUserLogin(userId);

        // 添加小程序登录方式
        assignMiniUserLogin(userId);

        return convertQBean(userTypeRelDAO.save(po));
    }

    @Override
    public boolean hasStaffRel(Long userId, Long staffId) {
        return userTypeRelDAO.findByUserIdAndUserTypeAndObjectTypeAndObjectId(userId, UserType.Staff, EntityObjectType.STAFF, staffId).isPresent();
    }

    @Override
    public void deleteStaffRel(Long userId, Long staffId) throws UserTypeRelException {
        val userTypeRelPO = userTypeRelDAO.findByUserIdAndUserTypeAndObjectTypeAndObjectId(userId, UserType.Staff, EntityObjectType.STAFF, staffId).orElse(null);
        if (userTypeRelPO != null) {
            userTypeRelDAO.delete(userTypeRelPO);
        }
    }

    @Override
    public boolean hasConsumerRel(Long userId) {
        return userTypeRelDAO.findByUserIdAndUserTypeAndObjectTypeAndObjectId(userId, UserType.Consumer, EntityObjectType.DEFAULT, 0L).isPresent();
    }

    @Override
    @Transactional
    public UserTypeRel createConsumerRel(Long userId) throws UserTypeRelException {
        // 验证关联关系是否已存在 已存在就不操作直接返回
        Optional<UserTypeRelPO> optional = userTypeRelDAO.findByUserIdAndUserTypeAndObjectTypeAndObjectId(userId, UserType.Consumer, EntityObjectType.DEFAULT, 0L);
        if (optional.isPresent()) {
            return convertQBean(optional.get());
        }

        UserTypeRelPO po = new UserTypeRelPO();

        po.setUserType(UserType.Consumer);
        po.setUserId(userId);
        // 消费者不需要关联对象
        po.setObjectType(EntityObjectType.DEFAULT);
        po.setObjectId(0L);

        // 一个事务内完成角色绑定
        sysUserRoleService.assignByCode(po.getUserId(), po.getUserType().getRoleCode());

        // 添加小程序登录方式
        assignMiniUserLogin(userId);

        return convertQBean(userTypeRelDAO.save(po));
    }

    // 添加小程序登录方式
    private void assignMiniUserLogin(Long userId) {
        SysUser sysUser = sysUserService.getByIdEnsure(userId);

        // 如果有设置密码 添加密码登录方式
        Optional<UserCredential> userCredentialOptional = userCredentialService.findUserDefault(userId);
        if (userCredentialOptional.isPresent()) {
            // 小程序端不开放用户名登录
//            if (StringUtils.isNotEmpty(sysUser.getUsername())) {
//                UserLoginCreator creator = UserLoginCreator
//                        .builder()
//                        .withUserId(userId)
//                        .withLoginName(sysUser.getUsername())
//                        .withLoginNameType(LoginNameType.USERNAME)
//                        .withLoginCheckType(LoginCheckType.FRONT_CREDENTIAL)
//                        .withLoginCheckId(userCredentialOptional.get().getId())
//                        .build();
//                userLoginService.saveIfAbsent(creator);
//            }
            if (StringUtils.isNotEmpty(sysUser.getMobile())) {
                UserLoginCreator creator = UserLoginCreator
                        .builder()
                        .withUserId(userId)
                        .withLoginName(sysUser.getMobile())
                        .withLoginNameType(LoginNameType.PHONE_NUM)
                        .withLoginCheckType(LoginCheckType.FRONT_CREDENTIAL)
                        .withLoginCheckId(userCredentialOptional.get().getId())
                        .build();
                userLoginService.saveIfAbsent(creator);
            }
        }

        // 如果有设置手机号 添加验证码登录方式
        if (StringUtils.isNotEmpty(sysUser.getMobile())) {
            UserLoginCreator creator = UserLoginCreator
                    .builder()
                    .withUserId(userId)
                    .withLoginName(sysUser.getMobile())
                    .withLoginNameType(LoginNameType.PHONE_NUM)
                    .withLoginCheckType(LoginCheckType.FRONT_VERIFY_CODE)
                    .withLoginCheckId(0L)
                    .build();
            userLoginService.saveIfAbsent(creator);
        }
    }

    // 添加后台登录方式
    private void assignAdminUserLogin(Long userId) {
        SysUser sysUser = sysUserService.getByIdEnsure(userId);

        // 如果有设置密码 添加密码登录方式
        Optional<UserCredential> userCredentialOptional = userCredentialService.findUserDefault(userId);
        if (userCredentialOptional.isPresent()) {
            {
                UserLoginCreator.Builder userLoginBuilder = UserLoginCreator.builder()
                        .withUserId(sysUser.getId())
                        .withLoginName(sysUser.getUsername())
                        .withLoginNameType(LoginNameType.USERNAME)
                        .withLoginCheckType(LoginCheckType.ADMIN_CREDENTIAL)
                        .withLoginCheckId(userCredentialOptional.get().getId());
                userLoginService.save(userLoginBuilder.build());
            }
            if (StringUtils.isNotEmpty(sysUser.getMobile())) {
                UserLoginCreator creator = UserLoginCreator
                        .builder()
                        .withUserId(userId)
                        .withLoginName(sysUser.getMobile())
                        .withLoginNameType(LoginNameType.PHONE_NUM)
                        .withLoginCheckType(LoginCheckType.ADMIN_CREDENTIAL)
                        .withLoginCheckId(userCredentialOptional.get().getId())
                        .build();
                userLoginService.saveIfAbsent(creator);
            }
        }

        // 如果有设置手机号 添加验证码登录方式
        if (StringUtils.isNotEmpty(sysUser.getMobile())) {
            UserLoginCreator creator = UserLoginCreator
                    .builder()
                    .withUserId(userId)
                    .withLoginName(sysUser.getMobile())
                    .withLoginNameType(LoginNameType.PHONE_NUM)
                    .withLoginCheckType(LoginCheckType.ADMIN_VERIFY_CODE)
                    .withLoginCheckId(0L)
                    .build();
            userLoginService.saveIfAbsent(creator);
        }

    }

    @Override
    public QResponse<UserTypeRel> findAll(QRequest request, QPage requestPage) {
        return convertQResponse(findAllInternal(request, requestPage));
    }

    @Override
    public List<UserTypeRel> findByUserType(UserType userType) {
        return userTypeRelDAO.findByUserType(userType).stream().map(this::convertQBean).collect(Collectors.toList());
    }

    @Override
    public Long countByUserType(UserType userType) {
        return userTypeRelDAO.countByUserType(userType);
    }

    @Override
    public Long countUser(UserType userType, LocalDateTime start, LocalDateTime end) {
        return userTypeRelDAO.countByUserTypeAndCreatedTimeBetween(userType, start, end);
    }

    private Page<UserTypeRelPO> findAllInternal(QRequest request, QPage requestPage) {
        return userTypeRelDAO.findAll(convertSpecification(request), convertPageable(requestPage));
    }

}
